
// This file is part of the mstp-lib library, available at http://code.google.com/p/mstp-lib/ 
// Copyright (c) 2011-2014 Adrian Gostin, distributed under the GNU General Public License v3.

#pragma once

#pragma unmanaged
	#include "stp.h"
#pragma managed

using namespace System;
using namespace System::ComponentModel;
using namespace System::Threading;

namespace STP 
{
	public enum class StpVersion
	{
		LegacySTP  = 0,
		RSTP = 2,
		MSTP = 3,
	};

	public enum class PortRole
	{
		Undefined	= STP_PORT_ROLE_UNKNOWN,
		Disabled	= STP_PORT_ROLE_DISABLED,
		Root		= STP_PORT_ROLE_ROOT,
		Designated	= STP_PORT_ROLE_DESIGNATED,
		Alternate	= STP_PORT_ROLE_ALTERNATE,
		Backup		= STP_PORT_ROLE_BACKUP,
		Master		= STP_PORT_ROLE_MASTER
	};

	public enum class FlushFdbType
	{
		Immediate,
		RapidAgeing,
	};



	public ref class BridgeWrapper
	{
	public:
		interface class ICallbackHandler
		{
			void EnableLearning (BridgeWrapper^ wrapper, unsigned int portIndex, unsigned int treeIndex, bool enable);
			void EnableForwarding (BridgeWrapper^ wrapper, unsigned int portIndex, unsigned int treeIndex, bool enable);
			void Transmit (BridgeWrapper^ wrapper, unsigned int portIndex, array<unsigned char>^ bpdu);
			void FdbFlush (BridgeWrapper^ wrapper, unsigned int portIndex, unsigned int treeIndex, FlushFdbType flushType);
			void DebugStrOut (BridgeWrapper^ wrapper, int portIndex, int treeIndex, String^ str, bool flush);
		};

	private:
		BRIDGE* _bridge;
		initonly ICallbackHandler^ _callbackHandler;
		void*	_bpduBeingTransmitted;
		unsigned int	_bpduBeingTransmittedLength;
		unsigned int	_bpduBeingTransmittedSourcePort;
		bool _disposed;
		unsigned int _bytesAllocated;

	private:

		#pragma region Callbacks
		// callbacks from MSTP
		delegate void  EnableLearningDelegate			(BRIDGE* bridge, unsigned int portIndex, unsigned int treeIndex, bool enable);
		delegate void  EnableForwardingDelegate			(BRIDGE* bridge, unsigned int portIndex, unsigned int treeIndex, bool enable);
		delegate void* TransmitGetBufferDelegate		(BRIDGE* bridge, unsigned int portIndex, unsigned int bpduSize);
		delegate void  TransmitReleaseBufferDelegate	(BRIDGE* bridge);
		delegate void  FlushFdbDelegate					(BRIDGE* bridge, unsigned int portIndex, unsigned int treeIndex, enum STP_FLUSH_FDB_TYPE flushType);
		delegate void  DebugStrOutDelegate				(BRIDGE* bridge, int portIndex, int treeIndex, const char* str, bool flush);
		delegate void* AllocAndZeroMemoryDelegate (unsigned int size);
		delegate void  FreeMemoryDelegate (void* p);

		// hold references to delegates to avoid garbage collection (at least that what samples from the Internet say)
		initonly EnableLearningDelegate^		EnableLearningCallback;
		initonly EnableForwardingDelegate^		EnableForwardingCallback;
		initonly TransmitGetBufferDelegate^		TransmitGetBufferCallback;
		initonly TransmitReleaseBufferDelegate^	TransmitReleaseBufferCallback;
		initonly FlushFdbDelegate^				FlushFdbCallback;
		initonly DebugStrOutDelegate^			DebugStrOutCallback;
		initonly AllocAndZeroMemoryDelegate^	AllocAndZeroMemoryCallback;
		initonly FreeMemoryDelegate^			FreeMemoryCallback;

		void  OnMstpLibEnableLearning			(BRIDGE* bridge, unsigned int portIndex, unsigned int treeIndex, bool enable);
		void  OnMstpLibEnableForwarding			(BRIDGE* bridge, unsigned int portIndex, unsigned int treeIndex, bool enable);
		void* OnMstpLibTransmitGetBuffer		(BRIDGE* bridge, unsigned int portIndex, unsigned int bpduSize);
		void  OnMstpLibTransmitReleaseBuffer	(BRIDGE* bridge);
		void  OnMstpLibFdbFlush					(BRIDGE* bridge, unsigned int portIndex, unsigned int treeIndex, STP_FLUSH_FDB_TYPE flushType);
		void  OnMstpLibDebugStrOut				(BRIDGE* bridge, int portIndex, int treeIndex, const char* str, bool flush);
		void* OnMstpLibAlloc (unsigned int size);
		void  OnMstpLibFree (void* p);
		#pragma endregion

	public:
		BridgeWrapper (UInt32 portCount, UInt32 treeCount, StpVersion protocolVersion, UInt64 bridgeAddress, UInt32 debugLogBufferSize, ICallbackHandler^ callbackHandler);
		virtual ~BridgeWrapper ();
		!BridgeWrapper ();

		void Start (unsigned int timestamp);
		void Stop (unsigned int timestamp);
		bool IsStarted ();
		bool GetPortEnabled (unsigned int portIndex);
		PortRole GetPortRole (unsigned int portIndex, unsigned int treeIndex);
		bool GetPortLearning (unsigned int portIndex, unsigned int treeIndex);
		bool GetPortForwarding (unsigned int portIndex, unsigned int treeIndex);
		bool GetPortOperEdge (unsigned int portIndex);
		bool GetPortOperPointToPointMAC (unsigned int portIndex);
		
		void EnableLogging (bool enable);

		void SetPortPriority (unsigned int portIndex, unsigned int treeIndex, unsigned char portPriority, unsigned int timestamp);
		unsigned char GetPortPriority (unsigned int portIndex, unsigned int treeIndex);
		unsigned short GetPortIdentifier (unsigned int portIndex, unsigned int treeIndex);

		void SetPortAdminEdge (unsigned int portIndex, bool adminEdge);
		bool GetPortAdminEdge (unsigned int portIndex);

		void SetBridgePriority (unsigned int treeIndex, unsigned short bridgePriority, unsigned int timestamp);
		unsigned short GetBridgePriority (unsigned int treeIndex);

		property unsigned int PortCount { unsigned int get (); }
		property unsigned int TreeCount { unsigned int get (); }

		property unsigned int BytesAllocated { unsigned int get (); }

		STP::StpVersion GetStpVersion ();
		void SetStpVersion (STP::StpVersion version);

		UInt64 GetBridgeAddress ();
		void SetBridgeAddress (UInt64 address);

		// -------------------
		// MST Config
		String^ GetMstConfigName ();
		String^ GetMstConfigDefaultName ();
		void SetMstConfigName (String^ name, unsigned int timestamp);
		void SetMstConfigDefaultName (unsigned int timestamp);
		bool GetMstConfigDefaultNameUsed ();

		unsigned short GetMstConfigRevisionLevel ();
		void SetMstConfigRevisionLevel (unsigned short revisionLevel, unsigned int timestamp);

		array<unsigned char>^ GetMstConfigTable ();
		void SetMstConfigTable (array<unsigned char>^ table, unsigned int timestamp);

		unsigned char GetTreeIndexFromVlanNumber (unsigned short vlanNumber);

		// ---------------------

		void OnOneSecondTick (unsigned int timestamp);
		void OnPortDisabled (unsigned int portIndex, unsigned int timestamp);
		void OnPortEnabled (unsigned int portIndex, unsigned int linkSpeedMegabitsPerSecond, bool fullDuplex, unsigned int timestamp);
		void OnBpduReceived (unsigned int portIndex, array<unsigned char>^ bpdu, unsigned int timestamp);
	};
}
